﻿// --------------------------------------------------------------------------------------------------------------------
// <copyright file="Api.svc.cs" company="Spenta Consulting">
//   (c) Copyright 2011
// </copyright>
// <summary>
//   StreetCare Api Service
// </summary>
// --------------------------------------------------------------------------------------------------------------------

namespace Spenta.StreetCare.MVC.Services
{
    #region Using Directives

    using System;
    using System.Linq;
    using System.ServiceModel.Activation;

    using Spenta.StreetCare.Core.IoC;
    using Spenta.StreetCare.Core.Logging;
    using Spenta.StreetCare.Core.Models;
    using Spenta.StreetCare.MVC.Services.Data;
    using Spenta.StreetCare.MVC.Services.Interfaces;

    #endregion

    /// <summary>
    /// StreetCare Api Service
    /// </summary>
    [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
    public class Api : IApi
    {
        /// <summary>
        /// Private store for the entities
        /// </summary>
        private StreetCareEntities entities;

        /// <summary>
        /// Gets the entities.
        /// </summary>
        /// <value>The entities.</value>
        private StreetCareEntities Entities
        {
            get
            {
                return this.entities ??
                       (this.entities =
                        new StreetCareEntities(IoCHelper.ConfigurationBag.GetConnectionString("StreetCareEntities")));
            }
        }

        /// <summary>
        /// Gets the user identity.
        /// </summary>
        /// <returns>The user identity</returns>
        public GetUserIdentityResponse GetUserIdentity()
        {
            // TODO: Select from DB?
            var result = new GetUserIdentityResponse
                             {
                                 User = System.Web.HttpContext.Current.Session["StreetCareUser"] as User
                             };
            return result;
        }

        /// <summary>
        /// Gets a customer by its hostname
        /// </summary>
        /// <param name="hostname">The hostname</param>
        /// <returns>The customer</returns>
        public GetCustomerByHostnameResponse GetCustomerByHostname(string hostname)
        {
            try
            {
                var result = this.Entities.Customers.Where(c => c.CustomerHostname.Equals(hostname)).FirstOrDefault();

                return new GetCustomerByHostnameResponse { Customer = result };
            }
            catch (Exception ex)
            {
                IoCHelper.Logger.WriteError(LogCategories.StreetCare, "Error getting customer", ex);
                return new GetCustomerByHostnameResponse { Fault = ServiceFault.Create(ex, ApiServiceCodes.ErrorGetCustomerByHostname) };
            }
        }

        /// <summary>
        /// Gets the categories.
        /// </summary>
        /// <param name="site">The site identificator</param>
        /// <returns>The list of categories</returns>
        public GetCategoriesResponse GetCategories(int site)
        {
            try
            {
                var result = this.Entities.Categories.Where(c => c.CategoryCustomerID.Equals(site));

                return new GetCategoriesResponse { Categories = result.ToList() };
            }
            catch (Exception ex)
            {
                IoCHelper.Logger.WriteError(LogCategories.StreetCare, "Error getting categories", ex);
                return new GetCategoriesResponse { Fault = ServiceFault.Create(ex, ApiServiceCodes.ErrorGetCategories) };
            }
        }

        /// <summary>
        /// Gets a list of a customer categories with its associated report count.
        /// </summary>
        /// <param name="customerId">The customer identificator</param>
        /// <returns>The list of categories sith the associated report count</returns>
        public GetCategoriesWithCountResponse GetCategoriesWithCount(int customerId)
        {
            try
            {
                var result = this.Entities.Categories.Where(c => c.CategoryCustomerID.Equals(customerId));

                var returnList = result.Select(category => new CategoryWithCount
                    {
                        Category = category,
                        ReportCount =
                            this.Entities.Reports.Count(
                                r => r.ReportCategoryID.Equals(category.CategoryID))
                    }).ToList();

                if (returnList.Count > 0)
                {
                    returnList[0].IsDefault = true;
                }

                return new GetCategoriesWithCountResponse { CategoriesWithCount = returnList };
            }
            catch (Exception ex)
            {
                IoCHelper.Logger.WriteError(LogCategories.StreetCare, "Error getting statuses with count", ex);
                return new GetCategoriesWithCountResponse { Fault = ServiceFault.Create(ex, ApiServiceCodes.ErrorGetCategoriesWithCount) };
            }
        }

        /// <summary>
        /// Gets the list of statuses associated with a customer
        /// </summary>
        /// <param name="customerId">The customer identificator.</param>
        /// <returns>List of statuses</returns>
        public GetStatusesResponse GetStatuses(int customerId)
        {
            try
            {
                var result = this.Entities.Status.Where(s => s.StatusCustomerID.Equals(customerId));

                return new GetStatusesResponse { Statuses = result.ToList() };
            }
            catch (Exception ex)
            {
                IoCHelper.Logger.WriteError(LogCategories.StreetCare, "Error getting statuses", ex);
                return new GetStatusesResponse { Fault = ServiceFault.Create(ex, ApiServiceCodes.ErrorGetCategories) };
            }
        }

        /// <summary>
        /// Gets the list of customer statuses with its associated report count
        /// </summary>
        /// <param name="customerId">The customer identificator.</param>
        /// <returns>List of statuses with its associated report count</returns>
        public GetStatusesWithCountResponse GetStatusesWithCount(int customerId)
        {
            try
            {
                var result = this.Entities.Status.Where(s => s.StatusCustomerID.Equals(customerId));

                var returnList = result.Select(status => new StatusWithCount
                                                            {
                                                                Status = status,
                                                                IsDirty = false,
                                                                ReportCount = this.Entities.Reports.Count(r => r.ReportStatusID.Equals(status.StatusID))
                                                            }).ToList();

                return new GetStatusesWithCountResponse { StatusesWithCount = returnList };
            }
            catch (Exception ex)
            {
                IoCHelper.Logger.WriteError(LogCategories.StreetCare, "Error getting statuses with count", ex);
                return new GetStatusesWithCountResponse { Fault = ServiceFault.Create(ex, ApiServiceCodes.ErrorGetStatusesWithCount) };
            }
        }

        /// <summary>
        /// Creates a report with the entered information.
        /// </summary>
        /// <param name="report">The report information.</param>
        /// <returns>The operation response</returns>
        public CreateReportResponse CreateReport(Report report)
        {
            try
            {
                // Set default status
                report.Status =
                    this.Entities.Status.Where(s => s.StatusCustomerID == report.ReportCustomerID).FirstOrDefault();
                report.ReportStatusWhen = DateTime.Now;

                this.Entities.Reports.AddObject(report);
                this.Entities.SaveChanges();

                IoCHelper.Logger.WriteInfo("Report created. ID: " + report.ReportID + ", Title: " + report.ReportTitle);

                return new CreateReportResponse { Report = report };
            }
            catch (Exception ex)
            {
                IoCHelper.Logger.WriteError("Error creating report", ex);
                return new CreateReportResponse { Fault = ServiceFault.Create(ex, ApiServiceCodes.ErrorCreateReport) };
            }
        }

        /// <summary>
        /// Updates a report's status
        /// </summary>
        /// <param name="reportId">The report id</param>
        /// <param name="newStatusId">The new status id</param>
        /// <param name="newImageUrl">The new image url</param>
        /// <returns>The operation result</returns>
        public UpdateReportStatusResponse UpdateReportStatus(int reportId, int newStatusId, string newImageUrl)
        {
            try
            {
                var reports = this.Entities.Reports.ToList();
                foreach (var report in reports)
                {
                    report.ReportStatusID = 2;
                }

                this.Entities.SaveChanges();

                return new UpdateReportStatusResponse();
            }
            catch (Exception ex)
            {
                IoCHelper.Logger.WriteError("Error updating report status", ex);
                return new UpdateReportStatusResponse
                    {
                        Fault = ServiceFault.Create(ex, ApiServiceCodes.ErrorUpdateReportStatus) 
                    };
            }
        }

        /// <summary>
        /// Gets the list of reports associated to a customer with he first available status
        /// </summary>
        /// <param name="customerId">The customer identificator.</param>
        /// <returns>The reports list</returns>
        public GetReportsResponse GetReports(int customerId)
        {
            try
            {
                var firstStatusId = this.Entities.Status.OrderBy(s => s.StatusID).FirstOrDefault(s => s.StatusCustomerID.Equals(customerId)).StatusID;
                var result = this.Entities.Reports.Where(r => r.ReportStatusID.Equals(firstStatusId));

                return new GetReportsResponse { Reports = result.ToList() };
            }
            catch (Exception ex)
            {
                IoCHelper.Logger.WriteError("Error getting reports", ex);
                return new GetReportsResponse { Fault = ServiceFault.Create(ex, ApiServiceCodes.ErrorGetReports) };
            }
        }

        /// <summary>
        /// Gets the list reports with the given status
        /// </summary>
        /// <param name="statusId">The status code.</param>
        /// <returns>The reports list</returns>
        public GetReportsByStatusResponse GetReportsByStatus(int statusId)
        {
            try
            {
                var result = this.Entities.Reports.Where(r => r.ReportStatusID.Equals(statusId));

                return new GetReportsByStatusResponse { Reports = result.ToList() };
            }
            catch (Exception ex)
            {
                IoCHelper.Logger.WriteError("Error getting reports by status", ex);
                return new GetReportsByStatusResponse { Fault = ServiceFault.Create(ex, ApiServiceCodes.ErrorGetReportsByStatus) };
            }
        }

        /// <summary>
        /// Gets the list reports with the given category
        /// </summary>
        /// <param name="categoryId">The category code.</param>
        /// <returns>The list of reports</returns>
        public GetReportsByCategoryResponse GetReportsByCategory(int categoryId)
        {
            try
            {
                var result = this.Entities.Reports.Where(r => r.ReportCategoryID.Equals(categoryId));

                return new GetReportsByCategoryResponse { Reports = result.ToList() };
            }
            catch (Exception ex)
            {
                IoCHelper.Logger.WriteError("Error getting reports by category", ex);
                return new GetReportsByCategoryResponse { Fault = ServiceFault.Create(ex, ApiServiceCodes.ErrorGetReportsByCategory) };
            }
        }

        /// <summary>
        /// Gets the customer by its identificator.
        /// </summary>
        /// <param name="customerId">The customer identificator</param>
        /// <returns>The customer</returns>
        public GetCustomerByIDResponse GetCustomerByID(int customerId)
        {
            try
            {
                var result = this.Entities.Customers.Where(c => c.CustomerID.Equals(customerId));

                return new GetCustomerByIDResponse { Customer = result.FirstOrDefault() };
            }
            catch (Exception ex)
            {
                IoCHelper.Logger.WriteError("Error getting customer", ex);
                return new GetCustomerByIDResponse { Fault = ServiceFault.Create(ex, ApiServiceCodes.ErrorGetCustomerByID) };
            }
        }

        /// <summary>
        /// Gets the latest comments associatd with a customer.
        /// </summary>
        /// <param name="customerId">The customer identificator.</param>
        /// <returns>The list of comments</returns>
        public GetLatestCommentsResponse GetLatestComments(int customerId)
        {
            try
            {
                var result = this.Entities.Comments.Where(c => c.Report.ReportCustomerID.Equals(customerId)).OrderByDescending(c => c.CommentWhen);

                return new GetLatestCommentsResponse { Comments = result.ToList() };
            }
            catch (Exception ex)
            {
                IoCHelper.Logger.WriteError("Error getting comments", ex);
                return new GetLatestCommentsResponse { Fault = ServiceFault.Create(ex, ApiServiceCodes.ErrorGetCommentsLatest) };
            }
        }

        /// <summary>
        /// Creates a new comment with the given information
        /// </summary>
        /// <param name="comment">The comment information</param>
        /// <returns>The operation result</returns>
        public CreateCommentResponse CreateComment(Comment comment)
        {
            try
            {
                this.Entities.Comments.AddObject(comment);
                this.Entities.SaveChanges();

                IoCHelper.Logger.WriteInfo("Comment created. ID: " + comment.CommentID + ", User: " + comment.User.UserID);

                return new CreateCommentResponse { Comment = comment };
            }
            catch (Exception ex)
            {
                IoCHelper.Logger.WriteError("Error creating comment", ex);
                return new CreateCommentResponse { Fault = ServiceFault.Create(ex, ApiServiceCodes.ErrorCreateComment) };
            }
        }

        /// <summary>
        /// Gets a user by the provider and identificator
        /// </summary>
        /// <param name="identityProvider">The identity provider</param>
        /// <param name="nameIdentifier">The name identifier</param>
        /// <returns>The user object</returns>
        public GetUserByProviderAndIdentificatorResponse GetUserByProviderAndIdentificator(string identityProvider, string nameIdentifier)
        {
            try
            {
                var result = this.Entities.Users.Where(u => u.UserIdentityProvider.Equals(identityProvider, StringComparison.OrdinalIgnoreCase) && u.UserNameIdentifier.Equals(nameIdentifier, StringComparison.OrdinalIgnoreCase)).First();

                return new GetUserByProviderAndIdentificatorResponse { User = result };
            }
            catch (Exception ex)
            {
                IoCHelper.Logger.WriteError(LogCategories.StreetCare, "Error getting user", ex);
                return new GetUserByProviderAndIdentificatorResponse { Fault = ServiceFault.Create(ex, ApiServiceCodes.ErrorGetUserByProviderAndIdentificator) };
            }
        }
    }
}
